using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Admin2022Soft2.Application.Common.Interface;
using Admin2022Soft2.Application.Configuration;
using Admin2022Soft2.Application.RequestDto;
using Admin2022Soft2.Application.ResponseDto;
using Admin2022Soft2.Domain.Entity;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;

namespace Admin2022Soft2.Infrastructrue.Identity
{
    public class IdentityService : IIdentityService
    {
        private readonly IConfiguration _configuration;
        private readonly IRepository<AppUser> _appUserRepository;
        private readonly IRepository<AppIdentityUser> _appIdnetityUserRepository;

        public IdentityService(IConfiguration configuration, IRepository<AppUser> appUserRepository, IRepository<AppIdentityUser> appIdnetityUserRepository)
        {
            _configuration = configuration;
            _appUserRepository = appUserRepository;
            _appIdnetityUserRepository = appIdnetityUserRepository;
        }
        public async Task<AppTokenDto> GenerateToken(AppUser appUser)
        {
            // 生成token，需要用户的id、用户名等信息
            var jwtSetting = _configuration.GetSection("JwtSetting").Get<JwtSetting>();
            var claims = new[]
           {
                new Claim("UserId",appUser!.Id.ToString()),
                new Claim("Username",appUser!.Username)
            };

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.Secret));
            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var securityToken = new JwtSecurityToken(jwtSetting.Issuer, jwtSetting.Audience, claims, expires: DateTime.UtcNow.AddMinutes(jwtSetting.AccessExpiration), signingCredentials: credentials);

            //生成token
            var token = new JwtSecurityTokenHandler().WriteToken(securityToken);
            var refreshToken = GenerateRefreshToken();

            var tmpIdentityUser = new AppIdentityUser
            {
                UserId = appUser.Id,
                Username = appUser.Username,
                RefreshToken = refreshToken,
                RefreshTokenExpiration = DateTime.UtcNow.AddMinutes(jwtSetting.RefreshExpiration)
            };

            var appIdentityUser=_appIdnetityUserRepository.Table.Where(x=>x.UserId==appUser.Id).ToList();
            await _appIdnetityUserRepository.DeleteBulkAsync(appIdentityUser,true);
            await _appIdnetityUserRepository.AddAsync(tmpIdentityUser);

            return new AppTokenDto
            {
                AccessToken = token,
                RefreshToken = refreshToken
            };
        }

        public async Task<AppTokenDto> RefreshTokenAsync(AppTokenDto appToken)
        {
            // 生成refreToken需要 过期的token和未过期的refreshToken
            var jwtSetting = _configuration.GetSection("JwtSetting").Get<JwtSetting>();
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,

                ValidIssuer = jwtSetting.Issuer,
                ValidAudience = jwtSetting.Audience,
                // ValidAudiences=au,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.Secret))
            };

            var tokenHandler = new JwtSecurityTokenHandler();
            var principal = tokenHandler.ValidateToken(appToken.AccessToken, tokenValidationParameters, out var securityToken);
            if (securityToken is not JwtSecurityToken jwtSecurityToken ||
                !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new SecurityTokenException("token无效");
            }

            // 更简单一些方式
            var username=principal.FindFirstValue("Username");

            // var claimIdentity = principal.Identity as ClaimsIdentity;

            // var username = claimIdentity!.FindFirst(x => x.Type == "Username")?.Value;

            // var realName = username == null ? "" : username;

            // 用从token中获得的用户名，从当前认证用户表中获取对应记录
            var user = _appIdnetityUserRepository.Table.FirstOrDefault(x => x.Username.Equals(username));
            if (user == null || user.RefreshToken != appToken.RefreshToken || user.RefreshTokenExpiration <= DateTime.Now)
            {
                throw new Exception("传入的token或者refreshToken无效");
            }

            var appUser = _appUserRepository.Table.FirstOrDefault(x => x.Username == username);

            if (appUser != null)
            {
                return await GenerateToken(appUser);
            }
            else
            {
                return new AppTokenDto();
            }

        }

        public  async Task<AppTokenDto> ValidateUserAsync(UserForAuthDto userForAuth)
        {
            // 使用传入的用户名和密码，验证用户名和密码是否都对，对则生成token，否则返回一个空token的对象
            var appUser = _appUserRepository.Table.FirstOrDefault(x => x.Username.Equals(userForAuth.Username)
            && x.Password.Equals(userForAuth.Password));
            if (appUser != null)
            {
                var appToken =await this.GenerateToken(appUser);
                return appToken;
            }
            else
            {
                return new AppTokenDto();
            }
        }

        private string GenerateRefreshToken()
        {
            // 创建一个随机的Token用做Refresh Token
            var rndNumber = new byte[32];

            using var rnd = RandomNumberGenerator.Create();
            rnd.GetBytes(rndNumber);

            return Convert.ToBase64String(rndNumber);
        }
    }
}